﻿using System;
using System.Windows;
using System.Windows.Media;
using System.Windows.Media.Media3D;
using Perspective.Wpf3D.Primitives;
using Perspective.Core.Primitives;
using Perspective.Core.Wpf;

namespace Perspective.Wpf3D.Sculptors
{
    /// <summary>
    /// 组成凹多边形的所有点和三角形集合
    /// A class to handle points and triangles of a concave polygonal model.
    /// Default radius is 1.0.
    /// </summary>
    public class ConcavePolygonSculptor : Sculptor
    {
        #region Constant
        internal const double DefaultCircumcircleRadius = 1.0;
        internal const double DefaultConcaveRadius = 0.2;
        #endregion

        #region Constructors
        /// <summary>
        /// Initializes a new instance of ConcavePolygonSculptor.
        /// </summary>
        public ConcavePolygonSculptor()
            : base()
        {
        }

         /// <summary>
        /// Initializes a new instance of ConcavePolygonSculptor.
        /// </summary>
        /// <param name="points">Points collection</param>
        public ConcavePolygonSculptor(Point3DCollection points)
            : base(points)
        {
        }

        /// <summary>
        /// Initializes a new instance of ConcavePolygonSculptor.
        /// </summary>
        /// <param name="points">Array of points</param>
        public ConcavePolygonSculptor(params Point3D[] points)
            : base(points)
        {
        }

        /// <summary>
        /// Initializes a new instance of ConcavePolygonSculptor.
        /// Vertices are automatically generated
        /// </summary>
        /// <param name="circumferenceBranchCount">Side count</param>
        /// <param name="initialAngle">Angle between the axis [origin - first point] and the X-axis, in degrees</param>
        public ConcavePolygonSculptor(int circumferenceBranchCount, double initialAngle)
        {
            _initialAngle = initialAngle;
            _circumferenceBranchCount = circumferenceBranchCount;
            CreatePoints();
        }

         /// <summary>
        /// Initializes a new instance of ConcavePolygonSculptor.
        /// Vertices are automatically generated
        /// </summary>
        /// <param name="circumcircleRadius">Circumcircle Radius</param>
        /// <param name="circumferenceBranchCount">Branch count</param>
        /// <param name="initialAngle">Angle between the axis [origin - first point] and the X-axis, in degrees</param>
        /// <param name="concaveRadius">Concave Radius</param>
        public ConcavePolygonSculptor(double circumcircleRadius, int circumferenceBranchCount, double initialAngle, double concaveRadius)
        {
            Initialize(circumcircleRadius, circumferenceBranchCount, initialAngle, concaveRadius);
        }

        /// <summary>
        /// Initializes an existing instance of ConcavePolygonSculptor.
        /// Vertices are automatically generated
        /// </summary>
        /// <param name="circumcircleRadius">Circumcircle Radius</param>
        /// <param name="circumferenceBranchCount">Branch count</param>
        /// <param name="initialAngle">Angle between the axis [origin - first point] and the X-axis, in degrees</param>
        /// <param name="concaveRadius">Concave Radius</param>
        public void Initialize(double circumcircleRadius, int circumferenceBranchCount, double initialAngle, double concaveRadius)
        {
            _circumcircleRadius = circumcircleRadius;
            _initialAngle = initialAngle;
            _circumferenceBranchCount = circumferenceBranchCount;
            _concaveRadius = concaveRadius;
            CreatePoints();
        }
        #endregion

        #region Properties

        #region Center 外接圆中心点

        private Point3D _center;
        /// <summary>
        /// The concave polygon's center point.
        /// </summary>
        public Point3D Center
        {
            get { return _center; }
            set { _center = value; }
        }

        #endregion

        #region InitialAngle 初始角度 

        private double _initialAngle;
        /// <summary>
        /// Initial angle (first point), in degrees.
        /// </summary>
        public double InitialAngle
        {
            get { return _initialAngle; }
            set { _initialAngle = value; }
        }

        #endregion

        #region Centered 几何图形是否有中心点

        private bool _centered;

        /// <summary>
        /// Indicates if the sculptor has a center point.
        /// </summary>
        protected bool Centered
        {
            get { return _centered; }
            set { _centered = value; }
        }

        #endregion

        #region CircumferenceBranchCount 圆周的点数

        private int _circumferenceBranchCount;
        /// <summary>
        /// 圆周的点数
        /// Gets or sets the Branch count of the circumference.
        /// </summary>
        protected int CircumferenceBranchCount
        {
            get { return _circumferenceBranchCount; }
            set { _circumferenceBranchCount = value; }
        }

        #endregion

        #region ConcaveRadius 凹点圆半径

        private double _concaveRadius = DefaultConcaveRadius;
        /// <summary>
        /// Gets or sets the radius of the concave circle.
        /// </summary>
        protected double ConcaveRadius
        {
            get { return _concaveRadius; }
            set { _concaveRadius = value; }
        }       
    
        #endregion

        #region CircumcircleRadius 外接圆半径

        private double _circumcircleRadius = DefaultCircumcircleRadius;
        /// <summary>
        /// Gets or sets the radius of the circumcircle.
        /// </summary>
        protected double CircumcircleRadius
        {
            get { return _circumcircleRadius; }
            set { _circumcircleRadius = value; }
        }

        #endregion

        #endregion

        #region Functions

        /// <summary>
        /// Initializes the Points and Triangles collections.
        /// Called By Sculptor.BuildMesh()
        /// </summary>
        protected override void CreateTriangles()
        {
            if (Points.Count == 0)
            {
                // CreatePoints(_circumferenceSideCount);
                CreatePoints();
            }
            if ((Triangles.Count == 0) &&
                (Points.Count > 0))
            {
                BuildTriangles();
            }
        }

         /// <summary>
        /// 计算圆(半径为1)等分点的点位集合
        /// Create the points of the polygon.
        /// </summary>
        protected virtual void CreatePoints()
        {
            if (_circumferenceBranchCount < 3)
            {
                throw new ArgumentException("_circumferenceBranchCount < 3");
            }
            this.Points.Clear();
            _center = new Point3D(0, 0, 0);
            _centered = true;
             double angle1Rad = 2 * Math.PI / _circumferenceBranchCount;
            double angleBranchHeadOffset = angle1Rad / 2;
            double angle = 0.0;
            for (int i = 1; i <= _circumferenceBranchCount; i++)
            {
                //base points
                angle = (angle1Rad * i) + GeometryHelper.DegreeToRadian(_initialAngle);
                Point3D p = new Point3D();
                p.X = Math.Cos(angle) * _circumcircleRadius;
                p.Y = Math.Sin(angle) * _circumcircleRadius;
                p.Z = 0;
                this.Points.Add(p);

                //head point
                // head point
                double angleBranchHead = angle + angleBranchHeadOffset;
                Point3D pBranch = new Point3D();
                pBranch.X = Math.Cos(angleBranchHead) * _concaveRadius;
                pBranch.Y = Math.Sin(angleBranchHead) * _concaveRadius;
                this.Points.Add(pBranch);
            }
        }

        /// <summary>
        /// Build the triangles.
        /// </summary>
        public void BuildTriangles()
        {
            BuildTriangles(TriangleSideKind.Front);
        }

          /// <summary>
        /// Build the triangles, with a specific side orientation.
        /// </summary>
        /// <param name="tsk">TriangleSideKind value (triangle orientation).</param>
        public virtual void BuildTriangles(TriangleSideKind tsk)
        {
            this.Triangles.Clear();
            if (Points.Count < 6)
            {
                throw new ArgumentException("Points.Count < 6");
            }

            // center based triangles
            for (int i = 0; i <= Points.Count - 1; i++)
            {
                if ((tsk & TriangleSideKind.Front) == TriangleSideKind.Front)
                {
                    if (i < Points.Count - 1)
                    {
                        this.Triangles.Add(new Point3DTriplet(_center, Points[i], Points[i + 1]));
                    }
                    else
                    {
                        this.Triangles.Add(new Point3DTriplet(_center, Points[i], Points[0]));
                    }
                }
                if ((tsk & TriangleSideKind.Back) == TriangleSideKind.Back)
                {
                    if (i < Points.Count - 1)
                    {
                        this.Triangles.Add(new Point3DTriplet(_center, Points[i + 1], Points[i]));
                    }
                    else
                    {
                        this.Triangles.Add(new Point3DTriplet(_center, Points[0], Points[i]));
                    }
                }
            }
        }

        /// <summary>
        /// A method for building the TextureCoordinates collection of the mesh.
        /// </summary>
        internal override void MapTexture()
        {
            foreach (Point3DTriplet pt in this.Triangles)
            {
                foreach (Point3D p in pt.Points)
                {
                    Mesh.TextureCoordinates.Add(
                        new Point(p.X, -p.Y));
                }
            }
        }
        #endregion
    }
}
